package com.jd.risk.bankorder.util.file;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class AbstractUploadManager <T, E extends Enum<? extends BasicConfigColumns>>{
	 
	private static final Logger LOGGER = LoggerFactory.getLogger(AbstractUploadManager.class);
	
	
    /**
     * @return 本类管理的实体对象类型
     */
    public abstract Class<T> getClasz();
	
	/**
     * 获取描述当前数据管理类所管理对象的枚举类
     * 
     * @return
     * @see BasicConfigColumns
     */
    public abstract Class<E> getColumn();

    /**
     * 从描述字段的枚举类中获取字段名称
     * 
     * @param column 字段描述类
     * @return 结果
     * @see BasicConfigColumns
     */
    private String getFieldName(E column) {
        return ((BasicConfigColumns) column).getColumnName();
    }

    /**
     * 从描述字段的枚举类中获取配置名称
     * 
     * @param column 字段描述类
     * @return 结果
     */
    private String getConfigName(E column) {
        return ((BasicConfigColumns) column).getConfigName();
    }

    /**
     * 将从配置文件中读取出的数据转换成指定字段类型，用于赋值
     * 
     * @param clasz 需要赋值的字段的类型
     * @param value 需要赋值给字段的原始值
     * @return 将要用来被赋值到指定字段的转换值
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    private Object castValue(Class<?> clasz, Object value) {
        Object result = null;
        if (value == null) {
            return null;
        }
        try {
            // 尝试强制转型
            return clasz.cast(value);
        } catch (ClassCastException e) {
        	LOGGER.warn("Auto cast failed origin type : " + value.getClass() + ", target type " + clasz);
        }
        // 尝试预设的转型方法
        if (clasz == String.class) {
            result = String.valueOf(value);
        } else if (clasz == Double.class) {
            result = Double.parseDouble(value.toString());
        } else if (clasz == Long.class) {
            if (value instanceof Double) {
                result = ((Double) value).longValue();
            }
        }
        if (result == null) {
            // 转型失败
        	LOGGER.warn( "Can't cast value origin type : " + value.getClass() + ", target type " + clasz);
        }
        return result;
    }

    /**
     * 将从配置文件读出出的数据转换成对象集合
     * 
     * @param configs 配置数据
     * @return 转换后的对象集合
     */
    public Collection<T> convertToBeans(Collection<Map<String, Object>> configs) {
        Collection<T> result = new ArrayList<T>();

        for (Map<String, Object> data : configs) {

            try {
                T bean = getClasz().newInstance();
                for (E column : getColumn().getEnumConstants()) {
                    String fieldName = getFieldName(column);
                    String configName = getConfigName(column);
                    Object valueToPut = data.get(configName);
                    if (valueToPut != null) {
                        Field field = getClasz().getDeclaredField(fieldName);
                        field.setAccessible(true);
                        field.set(bean, castValue(field.getType(), valueToPut));
                    }
                }
                result.add(bean);
            } catch (InstantiationException e) {
            	LOGGER.warn("", e);
            } catch (IllegalAccessException e) {
            	LOGGER.warn("", e);
            } catch (NoSuchFieldException e) {
            	LOGGER.warn("", e);
            } catch (SecurityException e) {
            	LOGGER.warn("", e);
            }
        }
        return result;
    }

    /**
     * 将对象集合转换成生成配置文件使用的数据集合
     * 
     * @param beans 数据集合
     * @return 结果
     */
    public Collection<Map<String, Object>> convertToMaps(Collection<T> beans) {
        Collection<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
        for (T bean : beans) {
            Map<String, Object> value = new HashMap<String, Object>();
            for (E column : getColumn().getEnumConstants()) {
                String fieldName = getFieldName(column);
                String configName = getConfigName(column);
                try {
                    Field field = getClasz().getDeclaredField(fieldName);
                    field.setAccessible(true);
                    value.put(configName, field.get(bean));
                } catch (NoSuchFieldException e) {
                	LOGGER.warn("", e);
                } catch (SecurityException e) {
                	LOGGER.warn("", e);
                } catch (IllegalArgumentException e) {
                	LOGGER.warn("", e);
                } catch (IllegalAccessException e) {
                	LOGGER.warn("", e);
                }
            }
            result.add(value);
        }
        return result;
    }

}
